package main

import (
	"errors"
	"fmt"
	"log"
	"time"

	"github.com/dgrijalva/jwt-go"
	"github.com/sirupsen/logrus"
)

var AppSecret = "123123" //盐，viper.GetString会设置这个值(32byte长度)
var AppIss = "Daived"    //发行人，这个值会被viper.GetString重写

// 自定义playload结构体
type userStdClaims struct {
	jwt.StandardClaims
}

// 生成token字符串
func JwtGenerateToken(userId int, d time.Duration) (string, error) {
	expireTime := time.Now().Add(d)  // 过期时间
	stdClaims := jwt.StandardClaims{ // 初始化载体
		ExpiresAt: expireTime.Unix(),
		IssuedAt:  time.Now().Unix(),
		Id:        fmt.Sprintf("%d", userId),
		Issuer:    AppIss,
	}

	uClaims := userStdClaims{
		StandardClaims: stdClaims,
	}

	//
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, uClaims)

	// Sign and get the complete encoded token as a string using the secret
	tokenString, err := token.SignedString([]byte(AppSecret))
	if err != nil {
		logrus.WithError(err).Fatal("config is wrong, can not generate jwt")
	}
	return tokenString, err
}

// 校验claims载体
func (c userStdClaims) Valid() (err error) {
	// 校验有效期
	if c.VerifyExpiresAt(time.Now().Unix(), true) == false {
		return errors.New("token is expired")
	}
	// 校验appIss
	if !c.VerifyIssuer(AppIss, true) {
		return errors.New("token's issuer is wrong")
	}
	// 校验是否登录（应该不会触发，未登录不返回token）
	if c.Id == "" {
		return errors.New("invalid user in jwt")
	}

	return
}

// token字符串转claims载体
func TokenParseClaims(tokenString string) (userStdClaims, error) {
	claims := userStdClaims{}
	if tokenString == "" {
		return claims, errors.New("no token is found in Authorization Bearer")
	}
	_, err := jwt.ParseWithClaims(tokenString, &claims, func(token *jwt.Token) (interface{}, error) {
		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
		}
		return []byte(AppSecret), nil
	})
	if err != nil {
		return claims, err
	}
	return claims, err
}

func main() {
	token, _ := JwtGenerateToken(1, time.Minute*20)
	fmt.Println(token)
	token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2MTY2NTEyMzYsImp0aSI6IjEiLCJpYXQiOjE2MTY2NTAwMzYsImlzcyI6IkRhaXZlZCJ9.ttHYmRyCb6969mKdPS5teU9PUl4C0mAG6niuwdZ6NdM"

	claims, err := TokenParseClaims(token)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(claims.Audience)
}
